package com.xiyi.shouxin.service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import com.xiyi.shouxin.controller.pojo.StatisticsView;
import com.xiyi.shouxin.controller.pojo.UserStatisticsView;
import com.xiyi.shouxin.dao.admin.AdminRepository;
import com.xiyi.shouxin.dao.admin.RoleRepository;
import com.xiyi.shouxin.dao.user.CprRepository;
import com.xiyi.shouxin.dao.user.PracticeRepository;
import com.xiyi.shouxin.dao.user.UserRepository;
import com.xiyi.shouxin.entity.admin.Admin;
import com.xiyi.shouxin.entity.admin.Role;
import com.xiyi.shouxin.entity.admin.mapper.AdminMapper;
import com.xiyi.shouxin.entity.admin.mapper.RoleMapper;
import com.xiyi.shouxin.entity.user.Cpr;
import com.xiyi.shouxin.entity.user.Practice;
import com.xiyi.shouxin.entity.user.RankData;
import com.xiyi.shouxin.entity.user.User;
import com.xiyi.shouxin.entity.user.mapper.PracticeMapper;
import com.xiyi.shouxin.entity.user.mapper.UserMapper;
import com.xiyi.shouxin.exception.CommonException;
import com.xiyi.shouxin.exception.ErrorCode;
import com.xiyi.shouxin.global.PracticeDataLimit;
import com.xiyi.shouxin.global.QualifiedEnum;
import com.xiyi.shouxin.global.RoleEnum;
import com.xiyi.shouxin.view.pojo.CprView;
import com.xiyi.shouxin.view.pojo.ItemPage;
import com.xiyi.shouxin.view.pojo.PracticeView;
import com.xiyi.shouxin.view.pojo.UserPracticeTimeView;
import com.xiyi.shouxin.view.pojo.UserView;

@Service
public class PracticeService {
    @Autowired
    private PracticeRepository practiceRepository;
    @Autowired
    private CprRepository cprRepository;
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private AdminRepository adminRepository;
    @Autowired
    private RoleRepository roleRepository;

    public ItemPage<PracticeView> findPracticeList(Long adminId, Long piciId, List<Long> pids, String keyword, Long uid,
            Date startTime, Date endTime, int page, int size, String sortCol, int order)
            throws Exception {
        List<PracticeView> list = new ArrayList<>();
        List<Practice> result = new ArrayList<>();
        int total = 0;
        Sort sort = Sort.by(Direction.DESC, "id");
        if (Strings.isNotBlank(sortCol) && order != 0) {
            if (order == 1) {
                sort = Sort.by(Direction.DESC, sortCol);
            }
            if (order == 2) {
                sort = Sort.by(Direction.ASC, sortCol);
            }
        }
        if (adminId != null) {
            Admin admin = adminRepository.findById(adminId, new AdminMapper());
            if (admin == null) {
                return new ItemPage<PracticeView>(list, total);
            }
            Role role = roleRepository.findById(admin.getRoleId(), new RoleMapper());
            if (role != null && RoleEnum.SUPER.getRole().equals(role.getRoleName())) {
                adminId = null;
            }
        }
        List<Long> ids = new ArrayList<>();
        if (StringUtils.hasText(keyword) || adminId != null) {
            ids = userRepository.selectIdsByAdminIdAndKeyword(adminId, keyword);
            if (ids == null || ids.isEmpty()) {
                return new ItemPage<PracticeView>(list, total);
            }
        }
        if (uid != null) {
            ids.clear();
            ids.add(uid);
        }

        result = practiceRepository.findByMultiConditionsByPage(ids, pids, null, piciId, startTime, endTime, sort,
                page, size);
        total = practiceRepository.countByMultiConditions(ids, pids, null, piciId, startTime, endTime);

        for (Practice practice : result) {
            User user = null;
            if (practice.getUid() != null) {
                user = userRepository.findById(practice.getUid(), new UserMapper());
            }
            PracticeView view = new PracticeView(practice, new UserView(user, null, null));

            Integer tt = 0;
            if (practice.getTotal() != null) {
                tt = tt + practice.getTotal();
            }
            // if (practice.getNotReset() != null) {
            // tt = tt + practice.getNotReset();
            // }
            view.setTotal(tt);
            // if (tt == 0 || practice.getQualifiedQuantity() == null) {
            // view.setPassRate(0d);
            // } else {
            // BigDecimal dividend = new
            // BigDecimal(practice.getQualifiedQuantity().toString());
            // BigDecimal divisor = new BigDecimal(tt);
            // view.setPassRate(
            // dividend.divide(divisor, 4, RoundingMode.HALF_UP).multiply(new
            // BigDecimal(100)).doubleValue());
            // }
            Double depth = cprRepository.avgDepthByPracticeId(practice.getId());
            if (depth == null) {
                view.setDepth(0d);
            } else {
                view.setDepth(depth);
            }

            if (practice.getTotal() == null || practice.getTotal() == 0 || practice.getTime() == null
                    || practice.getTime() == 0) {
                view.setNum(0d);
            } else {
                BigDecimal dividend = new BigDecimal(practice.getTotal().toString());
                BigDecimal divisor = new BigDecimal(practice.getTime());
                divisor = divisor.divide(new BigDecimal("60"), 2, RoundingMode.HALF_UP);
                if (divisor.doubleValue() == 0) {
                    view.setNum(0d);
                } else {
                    view.setNum(dividend.divide(divisor, 0, RoundingMode.HALF_UP).doubleValue());
                }
            }
            view.setRateCount(
                    cprRepository.countByPracticeIdBetweenTime(practice.getId(), PracticeDataLimit.FastRateTime,
                            PracticeDataLimit.SlowRateTime));
            view.setDepthCount(
                    cprRepository.countByPracticeIdAndGreaterThenDepth(practice.getId(), PracticeDataLimit.SlowDepth));

            list.add(view);
        }
        return new ItemPage<PracticeView>(list, total);
    }

    public ItemPage<CprView> findCprList(Long uid, Long practiceId, int page, int size)
            throws Exception {
        List<CprView> list = new ArrayList<>();
        List<Cpr> result = new ArrayList<>();
        int total = 0;
        Sort sort = Sort.by(Direction.ASC, "millisecond");

        result = cprRepository.findByMultiConditionsByPage(uid, practiceId, sort, page, size);
        total = cprRepository.countByMultiConditions(uid, practiceId);

        for (Cpr cpr : result) {
            list.add(new CprView(cpr));
        }
        return new ItemPage<CprView>(list, total);
    }

    public PracticeView findPractice(Long practiceId) throws Exception {
        if (practiceId == null) {
            throw new CommonException(ErrorCode.INVALIDPARAMTER);
        }
        Practice practice = practiceRepository.findById(practiceId, new PracticeMapper());
        if (practice != null) {
            User user = null;
            if (practice.getUid() != null) {
                user = userRepository.findById(practice.getUid(), new UserMapper());
            }
            PracticeView view = new PracticeView(practice, new UserView(user, null, null));
            Integer tt = 0;
            if (practice.getTotal() != null) {
                tt = tt + practice.getTotal();
            }
            // if (practice.getNotReset() != null) {
            // tt = tt + practice.getNotReset();
            // }
            view.setTotal(tt);
            // if (tt == 0 || practice.getQualifiedQuantity() == null) {
            // view.setPassRate(0d);
            // } else {
            // BigDecimal dividend = new
            // BigDecimal(practice.getQualifiedQuantity().toString());
            // BigDecimal divisor = new BigDecimal(tt);
            // view.setPassRate(
            // dividend.divide(divisor, 4, RoundingMode.HALF_UP).multiply(new
            // BigDecimal(100)).doubleValue());
            // }
            Double depth = cprRepository.avgDepthByPracticeId(practice.getId());
            if (depth == null) {
                view.setDepth(0d);
            } else {
                view.setDepth(depth);
            }
            Long avgTime = cprRepository.avgTimeByPracticeId(practice.getId());
            if (avgTime != null) {
                view.setQualified(calQualified(depth, avgTime.intValue()).getQualified());
            } else {
                view.setQualified(QualifiedEnum.LIGHTFAST.getQualified());
            }

            if (practice.getTotal() == null || practice.getTotal() == 0 || practice.getTime() == null
                    || practice.getTime() == 0) {
                view.setNum(0d);
            } else {
                BigDecimal dividend = new BigDecimal(practice.getTotal().toString());
                BigDecimal divisor = new BigDecimal(practice.getTime());
                divisor = divisor.divide(new BigDecimal("60"), 2, RoundingMode.HALF_UP);
                if (divisor.doubleValue() == 0) {
                    view.setNum(0d);
                } else {
                    view.setNum(dividend.divide(divisor, 0, RoundingMode.HALF_UP).doubleValue());
                }
            }
            view.setMaxDepth(cprRepository.maxDepthByPracticeId(practiceId));
            view.setMinDepth(cprRepository.minDepthByPracticeId(practiceId));
            Long maxTime = cprRepository.maxTimeByPracticeId(practiceId);
            if (maxTime != null) {
                BigDecimal dividend = new BigDecimal("60000");
                BigDecimal divisor = new BigDecimal(maxTime.toString());

                view.setMaxTime(dividend.divide(divisor, 0, RoundingMode.HALF_UP).doubleValue());

            }
            Long minTime = cprRepository.minTimeByPracticeId(practiceId);
            if (minTime != null) {
                BigDecimal dividend = new BigDecimal("60000");
                BigDecimal divisor = new BigDecimal(minTime.toString());

                view.setMinTime(dividend.divide(divisor, 0, RoundingMode.HALF_UP).doubleValue());

            }

            view.setRateCount(
                    cprRepository.countByPracticeIdBetweenTime(practiceId, PracticeDataLimit.FastRateTime,
                            PracticeDataLimit.SlowRateTime));
            view.setFastRateCount(
                    cprRepository.countByPracticeIdAndLessThenTime(practiceId, PracticeDataLimit.FastRateTime));
            view.setSlowRateCount(
                    cprRepository.countByPracticeIdAndGreaterThenTime(practiceId, PracticeDataLimit.SlowRateTime));
            view.setDepthCount(
                    cprRepository.countByPracticeIdAndGreaterThenDepth(practiceId, PracticeDataLimit.SlowDepth));
            view.setHeavyDepthCount(
                    cprRepository.countByPracticeIdAndGreaterThenDepth(practiceId, PracticeDataLimit.HeavyDepth));
            view.setSlowDepthCount(
                    cprRepository.countByPracticeIdAndLessThenDepth(practiceId, PracticeDataLimit.SlowDepth));

            return view;
        }
        return null;
    }

    // 过重也算合格
    public PracticeView findPracticeWithHeavy(Long practiceId) throws Exception {
        if (practiceId == null) {
            throw new CommonException(ErrorCode.INVALIDPARAMTER);
        }
        Practice practice = practiceRepository.findById(practiceId, new PracticeMapper());
        if (practice != null) {
            User user = null;
            if (practice.getUid() != null) {
                user = userRepository.findById(practice.getUid(), new UserMapper());
            }
            PracticeView view = new PracticeView(practice, new UserView(user, null, null));
            Integer tt = 0;
            if (practice.getTotal() != null) {
                tt = tt + practice.getTotal();
            }
            // if (practice.getNotReset() != null) {
            // tt = tt + practice.getNotReset();
            // }
            view.setTotal(tt);
            // Integer pass = 0;
            // if (practice.getQualifiedQuantity() != null) {
            // pass += practice.getQualifiedQuantity();
            // }
            // if (practice.getWeightNum() != null) {
            // pass += practice.getWeightNum();
            // }
            // if (tt == 0) {
            // view.setPassRate(0d);
            // } else {
            // BigDecimal dividend = new BigDecimal(pass.toString());
            // BigDecimal divisor = new BigDecimal(tt);
            // view.setPassRate(
            // dividend.divide(divisor, 4, RoundingMode.HALF_UP).multiply(new
            // BigDecimal(100)).doubleValue());
            // }
            Double depth = cprRepository.avgDepthByPracticeId(practice.getId());
            if (depth == null) {
                view.setDepth(0d);
            } else {
                view.setDepth(depth);
            }
            Long avgTime = cprRepository.avgTimeByPracticeId(practice.getId());
            if (avgTime != null) {
                view.setQualified(calQualified(depth, avgTime.intValue()).getQualified());
            } else {
                view.setQualified(QualifiedEnum.LIGHTFAST.getQualified());
            }

            if (practice.getTotal() == null || practice.getTotal() == 0 || practice.getTime() == null
                    || practice.getTime() == 0) {
                view.setNum(0d);
            } else {
                BigDecimal dividend = new BigDecimal(practice.getTotal().toString());
                BigDecimal divisor = new BigDecimal(practice.getTime());
                divisor = divisor.divide(new BigDecimal("60"), 2, RoundingMode.HALF_UP);
                if (divisor.doubleValue() == 0) {
                    view.setNum(0d);
                } else {
                    view.setNum(dividend.divide(divisor, 0, RoundingMode.HALF_UP).doubleValue());
                }
            }
            view.setMaxDepth(cprRepository.maxDepthByPracticeId(practiceId));
            view.setMinDepth(cprRepository.minDepthByPracticeId(practiceId));
            Long maxTime = cprRepository.maxTimeByPracticeId(practiceId);
            if (maxTime != null) {
                BigDecimal dividend = new BigDecimal("60000");
                BigDecimal divisor = new BigDecimal(maxTime.toString());

                view.setMaxTime(dividend.divide(divisor, 0, RoundingMode.HALF_UP).doubleValue());

            }
            Long minTime = cprRepository.minTimeByPracticeId(practiceId);
            if (minTime != null) {
                BigDecimal dividend = new BigDecimal("60000");
                BigDecimal divisor = new BigDecimal(minTime.toString());

                view.setMinTime(dividend.divide(divisor, 0, RoundingMode.HALF_UP).doubleValue());

            }

            view.setRateCount(
                    cprRepository.countByPracticeIdBetweenTime(practiceId, PracticeDataLimit.FastRateTime,
                            PracticeDataLimit.SlowRateTime));
            view.setFastRateCount(
                    cprRepository.countByPracticeIdAndLessThenTime(practiceId, PracticeDataLimit.FastRateTime));
            view.setSlowRateCount(
                    cprRepository.countByPracticeIdAndGreaterThenTime(practiceId, PracticeDataLimit.SlowRateTime));
            view.setDepthCount(
                    cprRepository.countByPracticeIdAndGreaterThenDepth(practiceId, PracticeDataLimit.SlowDepth));
            view.setHeavyDepthCount(
                    cprRepository.countByPracticeIdAndGreaterThenDepth(practiceId, PracticeDataLimit.HeavyDepth));
            view.setSlowDepthCount(
                    cprRepository.countByPracticeIdAndLessThenDepth(practiceId, PracticeDataLimit.SlowDepth));

            return view;
        }
        return null;
    }

    public UserPracticeTimeView sumUserTime(Long uid) throws Exception {
        if (uid == null) {
            throw new CommonException(ErrorCode.INVALIDPARAMTER);
        }
        Integer total = practiceRepository.sumTotalByUid(uid);
        Long time = practiceRepository.sumTimeByUid(uid);
        UserPracticeTimeView view = new UserPracticeTimeView();
        view.setTotal(total);
        view.setTime(time);
        if (view.getTotal() == null) {
            view.setTotal(0);
        }
        if (view.getTime() == null) {
            view.setTime(0L);
        } else {
            view.setTime(view.getTime() / 60);
        }
        return view;
    }

    public UserPracticeTimeView countUserRank(Long uid, Integer type) throws Exception {
        if (uid == null) {
            throw new CommonException(ErrorCode.INVALIDPARAMTER);
        }
        UserPracticeTimeView view = new UserPracticeTimeView();
        if (type == null || type == 0) {
            view.setRank(practiceRepository.countRankById(uid));
        } else {
            User user = userRepository.findById(uid, new UserMapper());
            if (user == null || user.getAdminId() == null || user.getAdminId() == 0) {
                view.setRank(0);
                return view;
            }
            List<Long> uids = userRepository.selectIdsByAdminId(user.getAdminId());
            if (uids == null || uids.isEmpty()) {
                view.setRank(1);
            } else {
                view.setRank(practiceRepository.countRankInTeamById(uid, uids));
            }
        }

        if (view.getRank() == null) {
            view.setRank(0);
        }
        return view;
    }

    /*
     * 开始练习
     */
    public Practice startPractice(Long uid, Long adminId, Long piciId) throws Exception {
        Practice practice = new Practice();
        practice.setUid(uid);
        practice.setPiciId(piciId);
        if (adminId != null && adminId != 0) {
            practice.setAdminId(adminId);
        }
        practice.setCreatedAt(Long.toString(new Date().getTime() / 1000));
        Long id = practiceRepository.create(practice);
        practice.setId(id);
        return practice;
    }

    /*
     * 开始考核练习
     */
    public Practice startCheckPractice(Long uid, Long adminId, Long piciId) throws Exception {
        Practice practice = new Practice();
        practice.setIsCheck(1);
        practice.setUid(uid);
        practice.setPiciId(piciId);
        if (adminId != null && adminId != 0) {
            practice.setAdminId(adminId);
        }
        practice.setCreatedAt(Long.toString(new Date().getTime() / 1000));
        Long id = practiceRepository.create(practice);
        practice.setId(id);
        return practice;
    }

    /*
     * 回弹不足
     */
    public void notrestPractice(Long practiceId) throws Exception {
        // 最后一条记录改为未复位
        cprRepository.notResetLastByPracticeIdOrderByCreateTime(practiceId);
        // practiceRepository.addNotrest(practiceId);
    }

    /*
     * 结束练习
     */
    @Transactional(rollbackFor = Exception.class)
    public void endPractice(Long uid, Long practiceId) throws Exception {
        Practice practice = practiceRepository.findById(practiceId, new PracticeMapper());
        if (practice == null) {
            return;
        }
        Cpr first = cprRepository.findFirstByPracticeIdOrderByCreateTime(practiceId);
        Cpr last = cprRepository.findLastByPracticeIdOrderByCreateTime(practiceId);
        if (first == null || last == null || !StringUtils.hasText(first.getCreatedAt())
                || !StringUtils.hasText(last.getCreatedAt())) {
            practiceRepository.delById(practiceId);
            return;
        }
        Long time = null;
        try {
            time = Long.parseLong(last.getCreatedAt()) - Long.parseLong(first.getCreatedAt());
        } catch (NumberFormatException e) {

        }
        if (time == null || time < PracticeDataLimit.TimeLimit) {// 练习时间少于30s,删除
            cprRepository.delByPracticeId(practiceId);
            practiceRepository.delById(practiceId);
            return;
        }
        practice.setTime(time / 1000);
        Integer total = cprRepository.countByPracticeId(practiceId);
        practice.setTotal(total);
        Integer qualifiedQuantity = cprRepository.countByPracticeIdAndQualified(practiceId,
                QualifiedEnum.QUALIFIED.getQualified());
        Integer notReset = cprRepository.countByPracticeIdAndQualified(practiceId,
                QualifiedEnum.NOTRESET.getQualified());
        Integer tooHeavy = cprRepository.countByPracticeIdAndQualified(practiceId,
                QualifiedEnum.TOOHEAVY.getQualified());
        if (total.intValue() > 0) {
            BigDecimal dividend = new BigDecimal(qualifiedQuantity.toString());
            BigDecimal divisor = new BigDecimal(total.toString());
            practice.setPassRate(
                    dividend.divide(divisor, 4, RoundingMode.HALF_UP).doubleValue());
        }
        practice.setQualifiedQuantity(qualifiedQuantity);
        practice.setNotReset(notReset);
        practice.setWeightNum(tooHeavy);
        User user = userRepository.findById(uid, new UserMapper());
        if (user != null) {
            practice.setDeviceId(user.getDeviceId());
        }
        practiceRepository.update(practiceId, practice);

        // 练习时间少于30s,删除
        List<Long> pids = practiceRepository.findAllNoTimePracticeByUid(uid, PracticeDataLimit.TimeLimit / 1000);
        if (pids != null && !pids.isEmpty()) {
            cprRepository.delByPracticeIds(pids);
            practiceRepository.delByIds(pids);
        }
    }

    public void practiceData(Cpr cpr) throws Exception {
        cprRepository.create(cpr);
    }

    // 计算质量
    public QualifiedEnum calQualified(Double depth, Integer time) {
        Double minDepth = PracticeDataLimit.SlowDepth;
        Double maxDepth = PracticeDataLimit.HeavyDepth;
        Integer minTime = 500;
        Integer maxTime = 600;
        if (depth >= minDepth && depth <= maxDepth && time >= minTime && time <= maxTime) {
            return QualifiedEnum.QUALIFIED;
        }
        if (depth < minDepth && time > maxTime) {
            return QualifiedEnum.LIGHTSLOW;
        }
        if (depth < minDepth && time < minTime) {
            return QualifiedEnum.LIGHTFAST;
        }
        if (depth > maxDepth && time > maxTime) {
            return QualifiedEnum.HEAVYSLOW;
        }
        if (depth > maxDepth && time < minTime) {
            return QualifiedEnum.HEAVYFAST;
        }
        if (depth < minDepth) {
            return QualifiedEnum.UNDERWEIGHT;
        }
        if (depth > maxDepth) {
            return QualifiedEnum.TOOHEAVY;
        }
        if (time > maxTime) {
            return QualifiedEnum.TOOSLOW;
        }
        if (time < minTime) {
            return QualifiedEnum.TOOFAST;
        }
        return QualifiedEnum.INVALID;
    }

    // 统计
    public StatisticsView statisticsPractice(Long adminId) throws Exception {
        StatisticsView view = new StatisticsView();
        if (adminId != null) {
            Admin admin = adminRepository.findById(adminId, new AdminMapper());
            if (admin == null) {
                return view;
            }
            Role role = roleRepository.findById(admin.getRoleId(), new RoleMapper());
            if (role != null && RoleEnum.SUPER.getRole().equals(role.getRoleName())) {
                adminId = null;
            }
        }
        Long totalUserNum = 0L;
        List<Long> ids = new ArrayList<>();
        if (adminId != null) {
            ids = userRepository.selectIdsByAdminIdAndKeyword(adminId, null);
            if (ids == null || ids.isEmpty()) {
                return view;
            }
            totalUserNum = (long) ids.size();
        } else {
            totalUserNum = userRepository.countTotal();
        }
        view.setTotalUserNum(totalUserNum);
        Long practiceNum = practiceRepository.countTotal(ids);
        view.setPracticeNum(practiceNum);
        Long qualifiedNum = practiceRepository.countQualified(ids);
        view.setQualifiedNum(qualifiedNum);
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        Date startTime = calendar.getTime();
        calendar.add(Calendar.HOUR_OF_DAY, 1);
        Date endTime = calendar.getTime();
        List<Long> userNumInDay = new ArrayList<>();
        List<Long> practiceNumInDay = new ArrayList<>();
        Date st = startTime;
        for (int i = 0; i <= 24; i++) {
            userNumInDay.add(practiceRepository.countUserNumByTime(ids, st, endTime));
            practiceNumInDay.add(practiceRepository.countNumByTime(ids, st, endTime));
            st = endTime;
            calendar.add(Calendar.HOUR_OF_DAY, 1);
            endTime = calendar.getTime();
        }
        view.setUserNumInDay(userNumInDay);
        view.setPracticeNumInDay(practiceNumInDay);
        Long todayNum = practiceRepository.countUserNumByTime(ids, startTime, endTime);
        view.setTodayNum(todayNum);
        return view;
    }

    // 用户年度数据统计
    public UserStatisticsView statisticsUserYearData(Long userId, int year) throws Exception {
        UserStatisticsView view = new UserStatisticsView();
        User user = userRepository.findById(userId, new UserMapper());
        if (user == null) {
            return view;
        }
        view.setUser(new UserView(user, null, null));
        List<Long> uIds = new ArrayList<>();
        uIds.add(userId);
        Long total = practiceRepository.countTotal(uIds);
        view.setTotalNum(total);

        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year);
        // 今年开始时间
        calendar.set(Calendar.DAY_OF_YEAR, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        Date startOfYear = calendar.getTime();

        // 今年结束时间
        calendar.set(Calendar.DAY_OF_YEAR, calendar.getActualMaximum(Calendar.DAY_OF_YEAR));
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        Date endOfYear = calendar.getTime();
        Long totalOfYear = practiceRepository.sumUserNumByTime(userId, startOfYear, endOfYear);
        view.setYearNum(totalOfYear);

        Long yearTime = practiceRepository.sumTimeByUidAndTime(userId, startOfYear, endOfYear);
        view.setYearTime(yearTime);
        Practice bestPractice = practiceRepository.findFirstByUserIdSort(userId, startOfYear, endOfYear,
                Sort.by(Direction.DESC, "pass_rate"));
        view.setBestPractice(new PracticeView(bestPractice, null));
        Practice longPractice = practiceRepository.findFirstByUserIdSort(userId, startOfYear, endOfYear,
                Sort.by(Direction.DESC, "time"));
        view.setLongPractice(new PracticeView(longPractice, null));
        Integer continuousNum = practiceRepository.countContinuousNum(userId, startOfYear, endOfYear);
        view.setContinuousNum(continuousNum);
        return view;
    }

    // 用户组合格率日排行
    public List<PracticeView> userGroupDailyPassRateRank(Long adminId, Date date) throws Exception {
        List<PracticeView> result = new ArrayList<>();
        if (adminId != null) {
            Admin admin = adminRepository.findById(adminId, new AdminMapper());
            if (admin == null) {
                return result;
            }
            Role role = roleRepository.findById(admin.getRoleId(), new RoleMapper());
            if (role != null && RoleEnum.SUPER.getRole().equals(role.getRoleName())) {
                adminId = null;
            }
        }
        if (date == null) {
            return result;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        // 开始时间
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        Date startTime = calendar.getTime();

        // 结束时间
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        Date endTime = calendar.getTime();
        List<RankData> list = practiceRepository.sumUserGroup(adminId, startTime, endTime);
        // 计算合格率
        for (RankData rd : list) {
            // if (rd.getTotal() == null || rd.getQualifiedQuantity() == null) {
            // continue;
            // }
            // rd.setPassRate(0d);
            // if (rd.getTotal() > 0) {
            // BigDecimal dividend = new BigDecimal(rd.getQualifiedQuantity().toString());
            // BigDecimal divisor = new BigDecimal(rd.getTotal().toString());
            // rd.setPassRate(
            // dividend.divide(divisor, 4, RoundingMode.HALF_UP).doubleValue());
            // }
            if (rd.getPassRate() == null) {
                rd.setPassRate(0d);
            }
        }
        // 排序，按合格率，再按合格数
        list.sort((p1, p2) -> {
            if (p1.getPassRate() > p2.getPassRate()) {
                return -1;
            } else if (p2.getPassRate() > p1.getPassRate()) {
                return 1;
            }
            int t1 = 0;
            if (p1.getQualifiedQuantity() != null) {
                t1 = p1.getQualifiedQuantity();
            }
            int t2 = 0;
            if (p2.getQualifiedQuantity() != null) {
                t2 = p2.getQualifiedQuantity();
            }
            return t2 - t1;
        });
        int rank = 1;
        RankData last = null;
        for (RankData rd : list) {
            User user = userRepository.findById(rd.getUid(), new UserMapper());
            PracticeView view = new PracticeView(null, new UserView(user, null, null));
            view.setUid(rd.getUid());
            view.setQualifiedQuantity(rd.getQualifiedQuantity());
            view.setTotal(rd.getTotal());
            view.setWeightNum(rd.getMaxTotal());
            view.setPassRate(rd.getPassRate());
            if (last == null) {
                last = rd;
                view.setRank(rank);
                result.add(view);
                continue;
            }
            int d1=(int)(rd.getPassRate()*100);
            int d2=(int)(last.getPassRate()*100);
            if (d1!=d2) {
                rank++;
            }
            last = rd;
            view.setRank(rank);
            result.add(view);
        }

        return result;
    }

    // 用户组有效数日排行
    public List<PracticeView> userGroupDailyQualifiedRank(Long adminId, Date date) throws Exception {
        List<PracticeView> result = new ArrayList<>();
        if (adminId != null) {
            Admin admin = adminRepository.findById(adminId, new AdminMapper());
            if (admin == null) {
                return result;
            }
            Role role = roleRepository.findById(admin.getRoleId(), new RoleMapper());
            if (role != null && RoleEnum.SUPER.getRole().equals(role.getRoleName())) {
                adminId = null;
            }
        }
        if (date == null) {
            return result;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        // 开始时间
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        Date startTime = calendar.getTime();

        // 结束时间
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        Date endTime = calendar.getTime();
        List<RankData> list = practiceRepository.sumUserGroup(adminId, startTime, endTime);
        // 排序，按最高有效数
        list.sort((p1, p2) -> {
            int t1 = 0;
            if (p1.getMaxTotal() != null) {
                t1 = p1.getMaxTotal();
            }
            int t2 = 0;
            if (p2.getMaxTotal() != null) {
                t2 = p2.getMaxTotal();
            }
            return t2 - t1;
        });
        int rank = 1;
        RankData last = null;
        for (RankData rd : list) {
            User user = userRepository.findById(rd.getUid(), new UserMapper());
            PracticeView view = new PracticeView(null, new UserView(user, null, null));
            view.setUid(rd.getUid());
            view.setQualifiedQuantity(rd.getQualifiedQuantity());
            view.setTotal(rd.getTotal());
            view.setMaxTotal(rd.getMaxTotal());
            if (last == null) {
                last = rd;
                view.setRank(rank);
                result.add(view);
                continue;
            }
            if (!rd.getMaxTotal().equals(last.getMaxTotal())) {
                rank++;
            }
            last = rd;
            view.setRank(rank);
            result.add(view);
        }

        return result;
    }

}
